/**********************************************************************************
 ***
 ***    Screencasting Teaching System C++ Library
 ***    Copyright (C) 2011  Jiri Novak <jiri.novak@petriny.net>
 ***                        Wadi Jalil Maluf <wadijm@gmail.com>
 ***
 ***    This file is part of the Screencasting Teaching System C++ Library.
 ***
 ***    This library is free software; you can redistribute it and/or modify
 ***    it under the terms of the GNU General Public License as published by
 ***   the Free Software Foundation; either version 3 of the License, or
 ***    (at your option) any later version.
 ***
 ***    This library is distributed in the hope that it will be useful,
 ***    but WITHOUT ANY WARRANTY; without even the implied warranty of
 ***    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ***   GNU General Public License for more details.
 ***
 ***    You should have received a copy of the GNU General Public License
 ***    along with this library; if not, write to the Free Software
 ***    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ***
 *********************************************************************************/

#include "screencasting_window.h"
#include "main_window.h"
#include "../serverservice.h"
#include "../common/model/chatmessage.h"
#include <cassert>
#include <iostream>
#include <cstdlib>

#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600

/**
 *
 */
ScreencastingWindow::ScreencastingWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder) :
	Gtk::Window(cobject),
	logger_(log4cxx::Logger::getLogger("client.gui.screencasting_window")),
	builder_(builder),
	videoEnabled_(false),
	surface_(0),
	player_(0),
	capturedLesson_(0) {
	initializeWidgets();
	makeConnections();
}

/**
 *
 */
ScreencastingWindow::~ScreencastingWindow() {
	if (player_) {
		delete player_;
	}
	if (surface_) {
		SDL_FreeSurface(surface_);
		SDL_Quit();
	}
}

/**
 *
 */
void ScreencastingWindow::updateTitle() {
	if (capturedLesson_) {
		std::string title = "Screencasting of lesson: '" + capturedLesson_->getName() + "' " + "for user: '" + userName_ + "'";
		set_title(title.c_str());
	}
}

/**
 *
 */
void ScreencastingWindow::initializeWidgets() {
	textViewEntry_ = 0;
	textViewMessages_ = 0;
	buttonSend_ = 0;
	hBox_ = 0;

	builder_->get_widget("screencasting_textview_entry", textViewEntry_);
	builder_->get_widget("screencasting_textview_messages", textViewMessages_);
	builder_->get_widget("screencasting_button_send", buttonSend_);
	builder_->get_widget("screencasting_hbox", hBox_);

	assert(textViewEntry_ != 0 && "textViewEntry_ pointer is null!");
	assert(textViewMessages_ != 0 && "textViewMessages_ pointer is null!");
	assert(buttonSend_ != 0 && "buttonSend_ pointer is null!");
	assert(hBox_ != 0 && "hBox_ pointer is null!");

	this->set_focus_child(*textViewEntry_);
}

/**
 *
 */
void ScreencastingWindow::makeConnections() {
	buttonSend_->signal_clicked().connect(sigc::mem_fun(*this, &ScreencastingWindow::sendChatMessage));
	this->signal_key_release_event().connect(sigc::mem_fun(*this, &ScreencastingWindow::onKeyPressed));
}

/**
 *
 */
bool ScreencastingWindow::onKeyPressed(GdkEventKey *event) {
	if (event->keyval == GDK_KEY_Return)
		sendChatMessage();
	return true;
}

/**
 *
 */
void ScreencastingWindow::play() {
	if (!player_)
		initializeSDL();

	if (player_)
		player_->start();
}

void ScreencastingWindow::stop() {
	if (player_) {
		player_->stop();
		player_->join();
	}
}

/**
 *
 */
bool ScreencastingWindow::initializeSDL() {
	int retval;

	// initialize GTK
	hBox_->add(socket_);
	hBox_->reorder_child(socket_, 0);

	// embed SDL surface to the GTK window
	std::stringstream sdlhack;
	sdlhack << "SDL_WINDOWID=" << socket_.get_id() << std::ends;
	char winhack[32];
	sprintf(&winhack[0], sdlhack.str().c_str(), "");
	SDL_putenv(winhack);
	LOG4CXX_DEBUG(logger_, "SDL asociated with GTK window.");

	// initialize SDL
	retval = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
	if (retval == -1) {
		LOG4CXX_FATAL(logger_, "could not initialize SDL - " << SDL_GetError());
		assert(retval != -1 && "could not initialize SDL - SDL_init returned -1");
	}

	// make a screen to put our video
	socket_.set_size_request(800, 600);
	surface_ = SDL_SetVideoMode(800, 600, 0, 0);
	show_all_children();

	if (surface_ == 0) {
		LOG4CXX_FATAL(logger_, "could not set video mode - create SDL surface: " << SDL_GetError());
		assert(surface_ != 0 && "could not set video mode - surface_ pointer is null!");
	}

	player_ = new VideoPlayer(surface_);
	videoEnabled_ = true;

	LOG4CXX_INFO(logger_, "SDL enabled");
	return true;
}

/**
 *
 */
void ScreencastingWindow::enqueueVideoPacket(std::vector<char> data, int pts) {
	if (videoEnabled_) {
		LOG4CXX_TRACE(logger_, "enqueueing video packet");
		player_->enqueueVideoPacket(data,pts);
	}
}

/**
 *
 */
void ScreencastingWindow::enqueueAudioPacket(std::vector<char> data, int pts) {
	LOG4CXX_TRACE(logger_, "enqueueing audio packet");
	if (videoEnabled_)
		player_->enqueueAudioPacket(data, pts);
}

/**
 *
 */
void ScreencastingWindow::sendChatMessage() {
	std::string message = textViewEntry_->get_buffer()->get_text().c_str();

	if (!message.empty()) {
		// send it to others
		ChatMessage chatMessage;
		chatMessage.setUser(userName_);
		chatMessage.setLesson(capturedLesson_->getId());
		chatMessage.setMessage(message);
		ServerService::getInstance().sentChatMessage(&chatMessage);
	}

	// clear the entry buffer
	textViewEntry_->get_buffer()->set_text("");
}

/**
 *
 */
void ScreencastingWindow::appendChatMessage(const std::string &userName, const std::string &message) {
	Lock l(appendChatMessageMutex_);
	std::string line2Show = "<" + userName + ">: " + message + "\n";
	Gtk::TextIter endIterator = textViewMessages_->get_buffer()->end();
	textViewMessages_->get_buffer()->insert(endIterator, line2Show.c_str());
}

/**
 *
 */
void ScreencastingWindow::displayChatMessage(ChatMessage *chatMessage) {
	assert(chatMessage != 0 && "chatMessage pointer is NULL!");
	appendChatMessage(chatMessage->getUser(), chatMessage->getMessage());

	delete chatMessage;
}
